home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TeX 1995 July
/
TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO
/
dviware
/
dvitovdu32
/
src
/
pascal
/
dvitovdu.p
< prev
next >
Wrap
Text File
|
1991-11-10
|
81KB
|
2,282 lines
PROGRAM DVItoVDU (output);
CONST version = 'This is DVItoVDU, version 3.0';
(* Author: Andrew Trevorrow
Implementation: Pyramid Pascal
Description:
This program allows pages from a DVI file produced by TeX to be previewed
on a VDU screen.
Notes:
- See AAAREAD.ME for revision history.
- Debugging code is bracketed by { DEBUG } ... { GUBED }.
This code will be commented out in the final working version.
- System-dependent code is indicated by the string "SYSDEP".
- Uncertain code is indicated by the string "???".
- Unfinished code is indicated by the string "!!!".
- Goto 999 is used to emulate a RETURN (from procedure) statement.
- Goto <= 888 is used to emulate an EXIT (from loop) statement.
- The above notes are also true for all separately compiled modules.
*)
#include 'globals.h';
#include 'screenio.h';
#include 'options.h';
#include 'vdu.h';
#include 'dvireader.h';
#include 'fontreader.h';
(* File access routines needed in ShowHelp: *)
CONST O_RDONLY = 0; (* SYSDEP: read-only flag for open;
value came from /usr/include/sys/fcntl.h *)
FUNCTION open (VAR path : string; flags, mode : integer) : integer; EXTERNAL;
FUNCTION read (f : integer; VAR ch : char; n : integer) : integer; EXTERNAL;
FUNCTION close (f : integer) : integer; EXTERNAL;
(*******************************************************************************
DECLARATIONS FOR PROCESSING USER COMMANDS
Most commands consist of one or two characters and can be entered
in upper or lowercase. Multiple commands are processed in the order
given but we only update the window, if necessary, at the end.
If a bad command is encountered, any further commands are ignored.
Some commands can have parameters; they are all dimensions in terms of the
current units. Spaces before and after commands and parameters are ignored.
*)
CONST
(* Possible commands are: *)
(* i a positive integer; display ith DVI page *)
TeXpage = '['; (* start of a TeX page specification: [i0. ... .i9] *)
NextPage = 'N'; (* display next DVI page, depending on direction *)
Forwards = '>'; (* process DVI pages in ascending order *)
Backwards = '<'; (* process DVI pages in descending order *)
Window = 'W'; (* move window's top left corner to given position *)
Up = 'U'; (* move window up a given amount *)
Down = 'D'; (* move window down a given amount *)
Left = 'L'; (* move window left a given amount *)
Right = 'R'; (* move window right a given amount *)
Hsize = 'H'; (* set scaledwd: window's horizontal size *)
Vsize = 'V'; (* set scaledht: window's vertical size *)
AutoView = 'A'; (* enable/disable automatic view after page selection *)
ZoomInOut = 'Z'; (* halve/double window dimensions *)
Terse = 'T'; (* display quick and nasty chars at reference points *)
Box = 'B'; (* display box outlines of glyphs *)
Full = 'F'; (* display all pixels in glyphs *)
Ic = 'I'; (* get/show dimensions in inches *)
Cm = 'C'; (* get/show dimensions in centimetres *)
Mm = 'M'; (* get/show dimensions in millimetres *)
PcPtPx = 'P'; (* get/show dimensions in picas/points/pixels *)
Help = '?'; (* display help on available commands *)
Show = 'S'; (* display useful statistics *)
Quit = 'Q'; (* have a guess *)
commprompt = 'Command:';
VAR
commstring : string; (* holds user responses *)
commpos : INTEGER; (* current position in commstring *)
commlen : INTEGER; (* length of commstring *)
command : CHAR; (* starting character of command *)
ascending : BOOLEAN; (* initially TRUE; changed by the
Forwards/Backwards commands to control
how to get the next DVI page *)
maxpix : INTEGER; (* maximum absolute pixel value;
depends on resolution *)
(* These flags are used to handle multiple commands: *)
screenjustcleared, (* has screen just been cleared? *)
paintDVIStatus, (* does DVI status line need updating? *)
paintWindowStatus, (* does window status line need updating? *)
paintwindow, (* does window region need updating? *)
pageoffpaper, (* is page off paper? *)
badcommand : BOOLEAN; (* was there a bad command? *)
(*******************************************************************************
DECLARATIONS FOR DISPLAYING A PAGE
The reference points of characters and rules on a page are stored as
pairs of horizontal and vertical paper pixel coordinates.
The paper coordinate scheme is described in detail in DVIReader.
The screen coordinate scheme is described in detail in VDU.
To update the window region, DVItoVDU maps visible paper pixels
to screen pixels using windowh and windowv to help with translation,
and windowwd and windowht to help with scaling.
What the user sees depends on the current displaymode, the current size
of the window region (scaledwd by scaledht are in paper pixels and determine
the horizontal and vertical scaling factors), and the current paper position
of the window region's top left corner; i.e., (windowleft,windowtop).
A NOTE ON THE SCALING METHOD USED BY DVItoVDU:
We desire the following conditions when scaling paper pixels to
screen pixels:
1. Rules/glyphs having the same top/bottom/left/right paper coordinates also
have the same screen coordinates (e.g., to ensure baselines line up).
This condition is incompatible with a rule/glyph staying the same
width and height as the window position changes! Too bad.
2. After being scaled, visible pixel positions must not exceed the
window region's edges. In our case, only the bottom and right edges are
a problem because scaling starts at the top left corner of the window.
We use two different scaling calculations depending on
whether the h/vscalefactors are < 1.0 or not.
3. Scaled heights and widths must be > 0 even when h/vscalefactors
approach 0. If h/vscalefactors are > 1.0 then the width/height of
paper pixels increase accordingly.
*)
VAR
displaymode : (tersemode (* show quick and nasty chars at ref pts *)
,boxmode (* show box outlines of glyphs *)
,fullmode (* show all pixels in glyphs *)
);
currentunits : (inunits (* get/show dimensions in inches *)
,cmunits (* get/show dimensions in centimetres *)
,mmunits (* get/show dimensions in millimetres *)
,pcunits (* get/show dimensions in picas *)
,ptunits (* get/show dimensions in points *)
,pxunits (* get/show dimensions in pixels *)
);
papertop,
paperleft,
paperbottom,
paperright : INTEGER; (* these define the edges of the paper *)
windowtop,
windowleft,
windowbottom,
windowright : INTEGER; (* these define the current window edges *)
allpagevisible : BOOLEAN; (* is all of page visible in window? *)
outsidepage : BOOLEAN; (* is entire window outside page? *)
scaledht : INTEGER; (* current window height in paper pixels *)
scaledwd : INTEGER; (* current window width in paper pixels *)
vscalefactor : REAL; (* windowht / scaledht *)
hscalefactor : REAL; (* windowwd / scaledwd *)
thisruleinfo : ruleinfoptr; (* current rule info in rulelist *)
unusedfont : fontinfoptr; (* first unused font in sorted fontlist *)
thisfontinfo : fontinfoptr; (* current font info in sorted fontlist *)
thischarinfo : charinfoptr; (* current char info in charlist *)
thischar : INTEGER; (* current index into current chartable *)
fontopen : BOOLEAN; (* is thisfontinfo^.fontspec open? *)
useraborted : BOOLEAN; (* did user abort page display? *)
autoviewing : BOOLEAN; (* automatic window view enabled? *)
(******************************************************************************)
PROCEDURE Initialize;
BEGIN
(* TeX will not generate dimensions > than about 38 feet, so we
choose an absolute limit on our dimensions to be 40 feet.
*)
maxpix := 40 * 12 * resolution;
(* top left corner of paper is fixed at (-1",-1") *)
papertop := -resolution;
paperleft := -resolution;
paperbottom := papertop + paperht - 1;
paperright := paperleft + paperwd - 1;
(* User sees the following status values before requesting the first page.
Note that DVIReader has already initialized currDVIpage and currTeXpage.
*)
ascending := TRUE; (* process DVI pages in ascending order *)
displaymode := tersemode;
windowtop := 0; (* window location *)
windowleft := 0;
scaledht := windowht; (* window size is initially unscaled *)
scaledwd := windowwd;
minhp := 0; minvp := 0; (* page location *)
maxhp := 0; maxvp := 0;
currentunits := inunits; (* units are initially inches *)
vscalefactor := 1.0;
hscalefactor := 1.0;
autoviewing := TRUE; (* start off enabled *)
END; (* Initialize *)
(******************************************************************************)
PROCEDURE ClearMessageLine;
(* Clear message line and move cursor to start of line.
We don't show any message here; that will usually be done
immediately after calling this routine.
*)
BEGIN
ClearTextLine(messagel);
MoveToTextLine(messagel);
END; (* ClearMessageLine *)
(******************************************************************************)
PROCEDURE WaitForReturn;
(* DVItoVDU has just displayed an important message.
To ensure message is seen we wait for user to hit Return.
*)
VAR ch : CHAR;
BEGIN
WriteString(' RETURN:');
WriteBuffer;
REPEAT ReadChar(ch) UNTIL ch = CR;
END; (* WaitForReturn *)
(******************************************************************************)
PROCEDURE UpdateDVIStatusLine;
(* Show totalpages, currDVIpage, currTeXpage, direction and displaymode. *)
LABEL 888;
VAR i, lastnonzero : INTEGER;
BEGIN
ClearTextLine(DVIstatusl);
MoveToTextLine(DVIstatusl);
WriteString('Total pages='); WriteInt(totalpages);
WriteString(' DVI page='); WriteInt(currDVIpage);
WriteString(' TeX page='); WriteChar('[');
lastnonzero := 9;
WHILE lastnonzero > 0 DO BEGIN
IF currTeXpage[lastnonzero] <> 0 THEN goto 888;
lastnonzero := lastnonzero - 1; (* find last counter with non-zero value *)
END;
888:
(* always show \count0 but don't show trailing 0 counters *)
FOR i := 0 TO lastnonzero DO BEGIN
WriteInt(currTeXpage[i]);
IF i <> lastnonzero THEN WriteChar('.');
END;
WriteChar(']');
WriteString(' Next=');
IF ascending THEN WriteChar('>') ELSE WriteChar('<');
WriteString(' Auto=');
IF autoviewing THEN WriteChar('+') ELSE WriteChar('-');
CASE displaymode OF
tersemode : WriteString(' Terse');
boxmode : WriteString(' Box') ;
fullmode : WriteString(' Full')
END;
WriteLine;
END; (* UpdateDVIStatusLine *)
(******************************************************************************)
PROCEDURE WriteDimension (pixels : INTEGER);
(* Show the given pixel dimension in terms of currentunits. *)
LABEL 999;
VAR realdim : REAL; fracpart : INTEGER;
BEGIN
CASE currentunits OF
inunits : realdim := pixels / resolution;
cmunits : realdim := pixels / resolution * 2.54;
mmunits : realdim := pixels / resolution * 25.4;
pcunits : realdim := pixels / resolution * 72.27 / 12.0;
ptunits : realdim := pixels / resolution * 72.27;
pxunits : BEGIN WriteInt(pixels); goto 999 END
END;
(* show realdim to an accuracy of 1 decimal place *)
IF ABS(realdim) < 0.05 THEN
WriteString('0.0')
ELSE BEGIN
IF realdim < 0.0 THEN BEGIN
WriteChar('-');
realdim := ABS(realdim);
END;
realdim := realdim + 0.05; (* round up to 1 decimal place *)
WriteInt(TRUNC(realdim)); (* whole part *)
WriteChar('.');
fracpart := TRUNC((realdim - TRUNC(realdim)) * 10.0); (* 0..9 *)
WriteInt(fracpart);
END;
999:
END; (* WriteDimension *)
(******************************************************************************)
PROCEDURE UpdateWindowStatusLine;
(* Show current window location and size, page location and size, and units. *)
BEGIN
ClearTextLine(windowstatusl);
MoveToTextLine(windowstatusl);
WriteString('Window at ('); WriteDimension(windowleft);
WriteChar(','); WriteDimension(windowtop);
WriteChar(')'); WriteChar(' '); WriteDimension(scaledwd);
WriteString(' by'); WriteChar(' '); WriteDimension(scaledht);
WriteString(' Page at ('); WriteDimension(minhp);
WriteChar(','); WriteDimension(minvp);
WriteChar(')'); WriteChar(' '); WriteDimension(maxhp-minhp+1);
WriteString(' by'); WriteChar(' '); WriteDimension(maxvp-minvp+1);
WriteChar(' '); WriteChar(' '); WriteChar(' ');
CASE currentunits OF
inunits : WriteString('IN');
cmunits : WriteString('CM');
mmunits : WriteString('MM');
pcunits : WriteString('PC');
ptunits : WriteString('PT');
pxunits : WriteString('PX')
END;
WriteLine;
END; (* UpdateWindowStatusLine *)
(******************************************************************************)
FUNCTION GetInteger (str : string; (* in *)
strlen : INTEGER; (* in *)
VAR pos : INTEGER; (* in/out *)
VAR n : INTEGER (* out *)
) : BOOLEAN;
(* Extract an integer from given str starting at given pos.
pos is also used to return the position after the integer.
If no integer is found then set n to 0 and return FALSE (pos will only
change if leading spaces were skipped).
If ABS(n) > limit then set n to sign * limit.
Valid syntax is +{digit} or -{digit} or digit{digit}.
Note that a + or - by itself is valid and sets n to 0.
*)
LABEL 777, 888;
CONST limit = 2147483647; (* TeX's limit = 2^31 - 1.
Should also be >= maxpix.
Note that this also defines the range of
page numbers the user can ask for! *)
threshold = limit DIV 10; (* nearing overflow *)
VAR absval, last : INTEGER;
sign : INTEGER;
inttoobig : BOOLEAN;
BEGIN
WHILE pos < strlen DO BEGIN (* skip any spaces *)
IF str[pos] <> ' ' THEN goto 888;
pos := pos + 1;
END;
888:
absval := 0; sign := 1; last := pos;
inttoobig := FALSE;
IF pos < strlen THEN BEGIN
IF str[pos] = '-' THEN BEGIN
sign := -1;
last := last + 1;
END
ELSE
IF str[pos] = '+' THEN last := last + 1;
WHILE last < strlen DO BEGIN
IF (str[last] < '0') OR (str[last] > '9') THEN goto 777;
IF (absval > threshold) OR
((absval = threshold) AND (str[last] > '7')) THEN
inttoobig := TRUE
ELSE
absval := absval * 10 + (ORD(str[last]) - ORD('0'));
last := last + 1;
END;
777:
END;
IF pos = last THEN BEGIN
n := 0;
GetInteger := FALSE;
END
ELSE BEGIN
pos := last;
IF inttoobig THEN absval := limit;
n := sign * absval;
GetInteger := TRUE;
END;
END; (* GetInteger *)
(******************************************************************************)
FUNCTION GetDimension (str : string; (* in *)
strlen : INTEGER; (* in *)
VAR pos : INTEGER; (* in/out *)
VAR n : INTEGER (* out *)
) : BOOLEAN;
(* Extract a dimension from given str starting at given pos.
n returns the corresponding number of pixels in the dimension
(which is an integer or real value in terms of currentunits);
pos is also used to return the position after the dimension.
If no dimension is found then set n to 0 and return FALSE (pos will only
change if leading spaces were skipped).
If ABS(n) > maxpix then set n to sign * maxpix.
Valid syntax of a dimension is integer[.{digit}] or .{digit} where
an integer is defined by GetInteger.
Real dimensions are truncated to 4 decimal places.
Note that a sign or decimal point by itself is valid and sets n to 0.
*)
LABEL 777, 888, 999;
VAR sign, intdim : INTEGER;
fracpart, divisor : INTEGER;
absrealdim : REAL;
intpresent, dimtoobig : BOOLEAN;
BEGIN
(* GetInteger does not remember a sign by itself, so we need to check
for -ve dimensions like -.5 first.
*)
WHILE pos < strlen DO BEGIN (* skip any spaces *)
IF str[pos] <> ' ' THEN goto 888;
pos := pos + 1;
END;
888:
sign := 1;
IF (pos < strlen) THEN
IF (str[pos] = '-') THEN
sign := -1;
intpresent := GetInteger(str,strlen,pos,intdim);
IF (NOT intpresent) THEN
IF ((pos = strlen) OR (str[pos] <> '.')) THEN BEGIN
n := 0;
GetDimension := FALSE;
goto 999;
END;
(* dimension is valid; if no integer part then intdim will be 0; sign = +|-1 *)
IF (pos = strlen) OR (str[pos] <> '.') THEN
(* no fractional part *)
absrealdim := ABS(intdim)
ELSE BEGIN
(* extract fractional part *)
pos := pos + 1; (* skip over decimal point *)
divisor := 1;
fracpart := 0;
WHILE pos < strlen DO BEGIN
IF (str[pos] < '0') OR (str[pos] > '9') THEN goto 777;
(* only consider up to 4 decimal places *)
IF divisor < 10000 THEN BEGIN
divisor := divisor * 10;
fracpart := fracpart * 10 + (ORD(str[pos]) - ORD('0'));
END;
pos := pos + 1;
END;
777:
absrealdim := ABS(intdim) + (fracpart / divisor);
END;
(* calculate n based on absrealdim, sign and currentunits *)
dimtoobig := FALSE;
CASE currentunits OF
inunits :
IF absrealdim > maxpix / resolution THEN
dimtoobig := TRUE
ELSE
n := sign * TRUNC(absrealdim * resolution + 0.5);
cmunits :
IF absrealdim > (maxpix / resolution) * 2.54 THEN
dimtoobig := TRUE
ELSE
n := sign * TRUNC((absrealdim / 2.54) * resolution + 0.5);
mmunits :
IF absrealdim > (maxpix / resolution) * 25.4 THEN
dimtoobig := TRUE
ELSE
n := sign * TRUNC((absrealdim / 25.4) * resolution + 0.5);
pcunits :
IF absrealdim > (maxpix / resolution) * (72.27 / 12.0) THEN
dimtoobig := TRUE
ELSE
n := sign * TRUNC((absrealdim / 72.27) * 12.0 * resolution + 0.5);
ptunits :
IF absrealdim > (maxpix / resolution) * 72.27 THEN
dimtoobig := TRUE
ELSE
n := sign * TRUNC((absrealdim / 72.27) * resolution + 0.5);
pxunits :
IF absrealdim > maxpix THEN
dimtoobig := TRUE
ELSE
n := sign * TRUNC(absrealdim + 0.5);
END;
IF dimtoobig THEN n := sign * maxpix;
GetDimension := TRUE;
999:
END; (* GetDimension *)
(******************************************************************************)
PROCEDURE BadCommandMessage;
(* A bad command has just been detected and some sort of message displayed.
Note that commpos is pointing to just after the problem character.
If there are further commands then we show user what will be ignored.
*)
VAR i : INTEGER;
BEGIN
badcommand := TRUE;
ClearTextLine(commandl);
MoveToTextLine(commandl);
WriteString(commprompt);
FOR i := 0 TO commpos-1 DO WriteChar(commstring[i]);
WriteChar('!'); (* put ! after the problem character *)
IF commpos < commlen THEN BEGIN
WriteString(' Ignoring:');
FOR i := commpos TO commlen-1 DO WriteChar(commstring[i]);
END;
WaitForReturn;
ClearMessageLine;
ClearTextLine(commandl);
END; (* BadCommandMessage *)
(******************************************************************************)
PROCEDURE NewLocation (newhp, newvp : INTEGER);
(* Change window location to given position and update window edges.
If entire window moves outside non-empty page rectangle then outsidepage
becomes TRUE and we restrict movement to just beyond the edge(s) so that
user can easily move window (via Up,Down,Left,Right) to positions
in which one or more window and page edges coincide.
Note that allpagevisible is also updated.
*)
BEGIN
outsidepage := FALSE;
IF (currDVIpage <> 0) AND (NOT pageempty) THEN BEGIN
(* check if new position puts window entirely outside edges;
if so then minimize the movement needed to keep this true *)
IF newvp > maxvp THEN BEGIN
outsidepage := TRUE;
newvp := maxvp + 1;
END
ELSE IF newvp < (minvp - scaledht + 1) THEN BEGIN
outsidepage := TRUE;
newvp := minvp - scaledht;
END;
IF newhp > maxhp THEN BEGIN
outsidepage := TRUE;
newhp := maxhp + 1;
END
ELSE IF newhp < (minhp - scaledwd + 1) THEN BEGIN
outsidepage := TRUE;
newhp := minhp - scaledwd;
END;
END;
windowtop := newvp;
windowleft := newhp;
windowbottom := windowtop + scaledht - 1;
windowright := windowleft + scaledwd - 1;
allpagevisible := (currDVIpage <> 0) AND (NOT pageempty) AND
(minvp >= windowtop) AND (maxvp <= windowbottom) AND
(minhp >= windowleft) AND (maxhp <= windowright);
(* even if pageempty or window hasn't moved we must still call DisplayPage *)
IF currDVIpage <> 0 THEN paintwindow := TRUE;
END; (* NewLocation *)
(******************************************************************************)
PROCEDURE WindowMove;
(* Syntax of Window command is W hpos,vpos where hpos and vpos are
dimensions with leading and/or trailing spaces. If hpos,vpos absent then
we move to minhp,minvp (top left corner of page rectangle).
*)
LABEL 888;
VAR hpos, vpos : INTEGER; (* move window to this new position *)
BEGIN
(* commpos is positioned after W *)
IF GetDimension(commstring,commlen,commpos,hpos) THEN BEGIN
WHILE commpos < commlen DO BEGIN
IF commstring[commpos] <> ' ' THEN goto 888;
commpos := commpos + 1; (* skip any spaces before comma *)
END;
888:
IF (commpos = commlen) OR (* , vpos is missing *)
(commstring[commpos] <> ',') THEN BEGIN (* , is missing *)
ClearMessageLine;
WriteString('Comma expected!');
IF commpos < commlen THEN commpos := commpos + 1;
BadCommandMessage;
END
ELSE BEGIN
commpos := commpos + 1; (* skip over comma *)
IF GetDimension(commstring,commlen,commpos,vpos) THEN
NewLocation(hpos,vpos)
ELSE BEGIN
ClearMessageLine;
WriteString('Vertical coordinate expected!');
IF commpos < commlen THEN commpos := commpos + 1;
BadCommandMessage;
END;
END;
END
ELSE
NewLocation(minhp,minvp); (* hpos,vpos absent *)
END; (* WindowMove *)
(******************************************************************************)
PROCEDURE WindowUpDown;
VAR amount : INTEGER; (* move window up/down this many pixels *)
BEGIN
(* commpos is positioned after U or D *)
IF GetDimension(commstring,commlen,commpos,amount) THEN
(* do nothing *)
ELSE
amount := scaledht; (* if amount absent, set to window height *)
IF command = Up THEN
amount := -amount;
NewLocation(windowleft,windowtop+amount);
END; (* WindowUpDown *)
(******************************************************************************)
PROCEDURE WindowLeftRight;
VAR amount : INTEGER; (* move window left/right this many pixels *)
BEGIN
(* commpos is positioned after L or R *)
IF GetDimension(commstring,commlen,commpos,amount) THEN
(* do nothing *)
ELSE
amount := scaledwd; (* if amount absent, set to window width *)
IF command = Left THEN
amount := -amount;
NewLocation(windowleft+amount,windowtop);
END; (* WindowLeftRight *)
(******************************************************************************)
PROCEDURE NewWindowWidth (wd : INTEGER);
(* Set window width to given value (> 0 and <= max dimension). *)
BEGIN
scaledwd := wd;
hscalefactor := windowwd / scaledwd;
END; (* NewWindowWidth *)
(******************************************************************************)
PROCEDURE SetWindowWidth;
(* Set horizontal size of window region to given dimension; if <= 0 then set
horizontal size to 1 pixel.
If no parameter then use the unscaled width represented by windowwd.
*)
VAR wd : INTEGER;
BEGIN
(* commpos is positioned after H *)
IF GetDimension(commstring,commlen,commpos,wd) THEN BEGIN
(* note that maximum value of wd is restricted to maxpix *)
IF wd <= 0 THEN wd := 1;
NewWindowWidth(wd);
END
ELSE
NewWindowWidth(windowwd); (* parameter absent *)
END; (* SetWindowWidth *)
(******************************************************************************)
PROCEDURE NewWindowHeight (ht : INTEGER);
(* Set window height to given value (> 0 and <= max dimension). *)
BEGIN
scaledht := ht;
vscalefactor := windowht / scaledht;
END; (* NewWindowHeight *)
(******************************************************************************)
PROCEDURE SetWindowHeight;
(* Set vertical size of window region to given dimension; if <= 0 then set
vertical size to 1 pixel.
If no parameter then use the unscaled height represented by windowht.
*)
VAR ht : INTEGER;
BEGIN
(* commpos is positioned after V *)
IF GetDimension(commstring,commlen,commpos,ht) THEN BEGIN
(* note that maximum value of ht is restricted to maxpix *)
IF ht <= 0 THEN ht := 1;
NewWindowHeight(ht);
END
ELSE
NewWindowHeight(windowht); (* parameter absent *)
END; (* SetWindowHeight *)
(******************************************************************************)
FUNCTION ScaleHpos (h : INTEGER) : INTEGER;
(* Return a scaled value for the given horizontal window coordinate. *)
BEGIN
IF hscalefactor > 1.0 THEN
ScaleHpos := TRUNC ( h * hscalefactor + 0.5 )
ELSE
ScaleHpos := TRUNC ( (h + 0.5) * hscalefactor ); (* hscalefactor <= 1.0 *)
END; (* ScaleHpos *)
(******************************************************************************)
FUNCTION ScaleVpos (v : INTEGER) : INTEGER;
(* Return a scaled value for the given vertical window coordinate. *)
BEGIN
IF vscalefactor > 1.0 THEN
ScaleVpos := TRUNC ( v * vscalefactor + 0.5 )
ELSE
ScaleVpos := TRUNC ( (v + 0.5) * vscalefactor ); (* vscalefactor <= 1.0 *)
END; (* ScaleVpos *)
(******************************************************************************)
PROCEDURE SetAutoView;
(* Parse the rest of an AutoView command and do it.
commpos is pointing to next position in commandstr (and should be + or -).
*)
VAR nextch : CHAR;
BEGIN
IF commpos < commlen THEN BEGIN
nextch := Cap(commstring[commpos]);
commpos := commpos + 1;
END
ELSE
nextch := ' ';
IF nextch = '+' THEN
autoviewing := TRUE
ELSE IF nextch = '-' THEN
autoviewing := FALSE
ELSE BEGIN
ClearMessageLine;
WriteString('A+ or A- expected!');
BadCommandMessage;
END;
END; (* SetAutoView *)
(******************************************************************************)
PROCEDURE ZoomWindow;
(* Parse the rest of a ZoomInOut command and do it.
commpos is pointing to next position in commandstr (and should be I or O).
*)
VAR nextch : CHAR;
BEGIN
IF commpos < commlen THEN BEGIN
nextch := Cap(commstring[commpos]);
commpos := commpos + 1;
END
ELSE
nextch := ' ';
IF nextch = 'I' THEN BEGIN
(* scaledwd and scaledht are > 0 *)
NewWindowWidth((scaledwd + 1) DIV 2);
NewWindowHeight((scaledht + 1) DIV 2);
END
ELSE IF nextch = 'O' THEN BEGIN
(* avoid overflow *)
IF maxpix DIV 2 > scaledwd THEN
NewWindowWidth(scaledwd * 2)
ELSE
NewWindowWidth(maxpix);
IF maxpix DIV 2 > scaledht THEN
NewWindowHeight(scaledht * 2)
ELSE
NewWindowHeight(maxpix);
END
ELSE BEGIN
ClearMessageLine;
WriteString('ZI or ZO expected!');
BadCommandMessage;
END;
END; (* ZoomWindow *)
(******************************************************************************)
FUNCTION NextPageFound : BOOLEAN;
(* User has selected next page in DVI file; what they get will depend on
the current DVI page and whether we are ascending or not.
Return TRUE iff we can move to next page.
*)
BEGIN
IF (currDVIpage = 1) AND (NOT ascending) THEN BEGIN
ClearMessageLine;
WriteString('You are looking at first DVI page!');
BadCommandMessage;
NextPageFound := FALSE;
END
ELSE IF (currDVIpage = totalpages) AND ascending THEN BEGIN
ClearMessageLine;
WriteString('You are looking at last DVI page!');
BadCommandMessage;
NextPageFound := FALSE;
END
ELSE BEGIN
MoveToNextPage(ascending); (* position to next DVI page *)
NextPageFound := TRUE;
END;
END; (* NextPageFound *)
(******************************************************************************)
FUNCTION DVIPageFound (n : INTEGER) : BOOLEAN;
(* User has selected a particular DVI page number.
Move to page n and return TRUE iff n is in 1..totalpages.
*)
BEGIN
IF (n < 1) OR (n > totalpages) THEN BEGIN
ClearMessageLine;
IF totalpages > 1 THEN BEGIN
WriteString('You can only request DVI pages 1 to'); WriteChar(' ');
WriteInt(totalpages); WriteChar('!');
END
ELSE
WriteString('You can only request DVI page 1!');
BadCommandMessage;
DVIPageFound := FALSE;
END
ELSE BEGIN
MoveToDVIPage(n); (* position to given DVI page *)
DVIPageFound := TRUE;
END;
END; (* DVIPageFound *)
(******************************************************************************)
FUNCTION ParseTeXpage (VAR newTeXpage : TeXpageinfo) : BOOLEAN;
(* Return TRUE iff TeX page specification in commstring is valid. If so then
newTeXpage will contain the appropriate information for MoveToTeXPage.
The syntax of a TeX page specification is [n{.n}] where n is any integer as
defined by GetInteger. Up to 10 integers may be given and are separated by
periods, even if absent. Trailing periods may be omitted. Spaces before
and after integers and periods are skipped. The 10 positions correspond to
the \count0, \count1, ... ,\count9 values that TeX stores with every page.
commpos is initially pointing at [.
*)
LABEL 666, 777, 888, 999;
BEGIN
WITH newTeXpage DO BEGIN
lastvalue := 0;
WHILE TRUE DO BEGIN
commpos := commpos + 1;
present[lastvalue] := GetInteger(commstring, commlen, commpos,
value[lastvalue]);
(* commpos now at commlen, space, period, non-digit or ']' *)
WHILE commpos < commlen DO BEGIN
IF commstring[commpos] <> ' ' THEN goto 888;
commpos := commpos + 1; (* skip any spaces *)
END;
888:
IF commpos = commlen THEN BEGIN (* check this first! *)
ClearMessageLine;
WriteString('] expected!');
BadCommandMessage; (* commpos at commlen *)
ParseTeXPage := FALSE;
goto 999;
END;
IF commstring[commpos] = ']' THEN BEGIN (* end of TeX page spec *)
commpos := commpos + 1;
goto 777;
END;
IF lastvalue < 9 THEN
lastvalue := lastvalue + 1
ELSE BEGIN
ClearMessageLine;
WriteString('] expected after 10 integers!');
commpos := commpos + 1;
BadCommandMessage;
ParseTeXPage := FALSE;
goto 999;
END;
IF commstring[commpos] <> '.' THEN BEGIN
ClearMessageLine;
WriteString('Period, integer or ] expected!');
commpos := commpos + 1;
BadCommandMessage;
ParseTeXPage := FALSE;
goto 999;
END;
END;
777:
WHILE lastvalue > 0 DO BEGIN
IF present[lastvalue] THEN goto 666;
lastvalue := lastvalue - 1;
END;
666:
END;
ParseTeXPage := TRUE;
999:
END; (* ParseTeXpage *)
(******************************************************************************)
FUNCTION TeXPageFound : BOOLEAN;
(* Return TRUE iff TeX page specification is valid and exists.
If so then position to lowest matching page.
*)
VAR newTeXpage : TeXpageinfo;
BEGIN
IF ParseTeXpage(newTeXpage) THEN
IF MoveToTeXPage(newTeXpage) THEN
TeXPageFound := TRUE (* we found lowest matching page *)
ELSE BEGIN
ClearMessageLine;
WriteString('No TeX page matches your request!');
BadCommandMessage;
TeXPageFound := FALSE;
END
ELSE
TeXPageFound := FALSE; (* invalid TeX page specification *)
END; (* TeXPageFound *)
(******************************************************************************)
FUNCTION Min (a, b : INTEGER) : INTEGER;
(* Return the minimum value of a and b. *)
BEGIN
IF a < b THEN Min := a ELSE Min := b;
END; (* Min *)
(******************************************************************************)
FUNCTION Max (a, b : INTEGER) : INTEGER;
(* Return the maximum value of a and b. *)
BEGIN
IF a > b THEN Max := a ELSE Max := b;
END; (* Max *)
(******************************************************************************)
PROCEDURE ProcessPage;
(* We are ready to interpret the current DVI page and fill in the various data
structures imported from DVIReader. This routine will also:
set the window size and location to useful values (if autoviewing),
update pageoffpaper (after checking to see if it was TRUE for the previous
page processed as part of a multiple command string),
set screenjustcleared, paintwindow and paintWindowStatus to TRUE,
set paintDVIStatus to FALSE.
*)
VAR halfht, halfwd : INTEGER;
BEGIN
(* We check pageoffpaper here so user can type "NNNNNNNNNNNNN..." and note ALL
the pages that are off the paper, not just the last one processed.
*)
IF pageoffpaper THEN BEGIN
ClearMessageLine;
WriteString('Page off paper!'); (* the previous page *)
WaitForReturn;
END;
ClearScreen;
screenjustcleared := TRUE;
UpdateDVIStatusLine; (* a MoveTo... routine has updated currDVI/TeXpage *)
paintDVIStatus := FALSE;
InterpretPage; (* fill in DVIReader's page data structures *)
SortFonts(unusedfont); (* sort fonts in order of least chars and return
pointer to first unused font *)
ClearMessageLine; (* clear any message *)
IF pageempty THEN BEGIN
minhp := 0; maxhp := 0; minvp := 0; maxvp := 0; (* for window status *)
END;
IF autoviewing THEN BEGIN
(* view as much of paper as possible but without too much distortion *)
IF ((paperwd < paperht) AND (windowwd >= windowht)) OR
((paperwd = paperht) AND (windowwd > windowht)) THEN BEGIN
halfht := paperht DIV 2;
IF ODD(paperht) THEN halfht := halfht + 1; (* ensure bottom visible *)
NewWindowHeight(halfht); (* try top half of paper *)
NewWindowWidth(paperwd);
NewLocation(paperleft,papertop); (* top left corner of paper *)
IF (NOT pageempty) AND outsidepage THEN
NewLocation(paperleft,papertop+halfht); (* try moving down *)
END
ELSE IF ((paperwd > paperht) AND (windowwd <= windowht)) OR
((paperwd = paperht) AND (windowwd < windowht)) THEN BEGIN
halfwd := paperwd DIV 2;
IF ODD(paperwd) THEN halfwd := halfwd + 1; (* ensure right visible *)
NewWindowHeight(paperht);
NewWindowWidth(halfwd); (* try left half of paper *)
NewLocation(paperleft,papertop); (* top left corner of paper *)
IF (NOT pageempty) AND outsidepage THEN
NewLocation(paperleft+halfwd,papertop); (* try moving right *)
END
ELSE BEGIN
(* paper shape matches unscaled window shape *)
NewWindowHeight(paperht); (* try all of paper *)
NewWindowWidth(paperwd);
NewLocation(paperleft,papertop); (* top left corner of paper *)
END;
END
ELSE BEGIN
(* not autoviewing, so use current window location and size *)
NewWindowHeight(scaledht);
NewWindowWidth(scaledwd);
NewLocation(windowleft,windowtop);
END;
(* check if part/all of page is off paper;
if so, and autoviewing is enabled, then we set window size and location
so user can just see ALL of paper AND ALL of page.
*)
pageoffpaper := (NOT pageempty) AND
((minhp < paperleft) OR (minvp < papertop) OR
(maxhp > paperright) OR (maxvp > paperbottom));
IF pageoffpaper AND autoviewing THEN BEGIN
NewWindowHeight (Max(maxvp,paperbottom) - Min(minvp,papertop) + 1);
NewWindowWidth (Max(maxhp,paperright) - Min(minhp,paperleft) + 1);
NewLocation (Min(minhp,paperleft),Min(minvp,papertop));
END;
paintWindowStatus := TRUE;
paintwindow := TRUE;
END; (* ProcessPage *)
(******************************************************************************)
PROCEDURE ChangeUnits;
(* Parse the rest of an Ic, Cm, Mm or PcPtPx command.
commpos is pointing to next position in commstring.
*)
VAR nextch : CHAR;
BEGIN
IF commpos < commlen THEN BEGIN
nextch := Cap(commstring[commpos]);
commpos := commpos + 1;
END
ELSE
nextch := ' ';
IF (command = Ic) AND (nextch = 'N') THEN currentunits := inunits
ELSE IF (command = Cm) AND (nextch = 'M') THEN currentunits := cmunits
ELSE IF (command = Mm) AND (nextch = 'M') THEN currentunits := mmunits
ELSE IF (command = PcPtPx) AND (nextch = 'C') THEN currentunits := pcunits
ELSE IF (command = PcPtPx) AND (nextch = 'T') THEN currentunits := ptunits
ELSE IF (command = PcPtPx) AND (nextch = 'X') THEN currentunits := pxunits
ELSE BEGIN
ClearMessageLine;
WriteString('Unknown units!');
WriteChar(' '); WriteChar(' '); WriteChar(' ');
CASE command OF
Ic : WriteString('IN');
Cm : WriteString('CM');
Mm : WriteString('MM');
PcPtPx : WriteString('PC, PT or PX')
END;
WriteString(' expected.');
BadCommandMessage;
END;
END; (* ChangeUnits *)
(******************************************************************************)
FUNCTION UserHitsReturn (VAR linecount : INTEGER) : BOOLEAN;
(* Do a WriteLine and return TRUE iff linecount = bottoml-2 AND user hits CR.
If linecount < bottoml-2 then return FALSE; if not, and user hits
something other than CR, then prepare a new screen before returning FALSE.
*)
LABEL 999;
VAR ch : CHAR;
BEGIN
WriteLine;
IF linecount = bottoml-2 THEN BEGIN (* prompt for next screen *)
MoveToTextLine(bottoml);
WriteString('Hit RETURN key to resume page display,');
WriteString(' or any other key for more:');
WriteBuffer;
ReadChar(ch);
IF ch = CR THEN BEGIN UserHitsReturn := TRUE; goto 999 END;
ClearScreen;
MoveToTextLine(1);
linecount := 1;
END
ELSE
linecount := linecount + 1;
UserHitsReturn := FALSE;
999:
END; (* UserHitsReturn *)
(******************************************************************************)
PROCEDURE WriteUnits;
BEGIN
CASE currentunits OF
inunits : WriteString('in');
cmunits : WriteString('cm');
mmunits : WriteString('mm');
pcunits : WriteString('pc');
ptunits : WriteString('pt');
pxunits : WriteString('px')
END;
END; (* WriteUnits *)
(******************************************************************************)
PROCEDURE WritePtSize (scaledsize : INTEGER);
(* Show given font size (in DVI units) in terms of (possibly magnified) pts. *)
VAR realdim : REAL; fracpart : INTEGER;
BEGIN
WriteString(' at'); WriteChar(' ');
realdim := (scaledsize / 16#10000) * (mag / 1000.0);
(* show realdim to an accuracy of 1 decimal place *)
IF ABS(realdim) < 0.05 THEN
WriteChar('0')
ELSE BEGIN
IF realdim < 0.0 THEN BEGIN
WriteChar('-');
realdim := ABS(realdim);
END;
realdim := realdim + 0.05; (* round up to 1 decimal place *)
WriteInt(TRUNC(realdim)); (* whole part *)
fracpart := TRUNC((realdim - TRUNC(realdim)) * 10.0); (* 0..9 *)
IF fracpart > 0 THEN BEGIN
WriteChar('.');
WriteInt(fracpart);
END;
END;
WriteString('pt');
END; (* WritePtSize *)
(******************************************************************************)
PROCEDURE ShowStatistics;
(* Show option values and font/character/rule/special statistics.
UserHitsReturn controls pagination and takes the place of WriteLine.
*)
LABEL 999;
VAR temp : specialinfoptr; linecount, fontcount : INTEGER; ch : CHAR;
BEGIN
ClearScreen;
MoveToTextLine(1);
linecount := 1;
WriteString('DVI file ='); WriteChar(' '); WriteString(DVIname);
IF UserHitsReturn(linecount) THEN goto 999;
WriteString('VDU ='); WriteChar(' '); WriteString(vdu);
IF UserHitsReturn(linecount) THEN goto 999;
WriteString('Resolution ='); WriteChar(' '); WriteInt(resolution);
WriteString(' pixels per inch');
IF UserHitsReturn(linecount) THEN goto 999;
WriteString('Magnification ='); WriteChar(' '); WriteInt(mag);
IF mag <> DVImag THEN BEGIN
WriteString(' (DVI mag of'); WriteChar(' '); WriteInt(DVImag);
WriteString(' was overridden)');
END
ELSE
WriteString(' (DVI mag)');
IF UserHitsReturn(linecount) THEN goto 999;
WriteString('TFM directory ='); WriteChar(' '); WriteString(tfmdir);
IF UserHitsReturn(linecount) THEN goto 999;
WriteString('PS font prefix ='); WriteChar(' '); WriteString(psprefix);
IF UserHitsReturn(linecount) THEN goto 999;
WriteString('Font directory ='); WriteChar(' '); WriteString(fontdir);
IF UserHitsReturn(linecount) THEN goto 999;
WriteString('Dummy font ='); WriteChar(' '); WriteString(dummyfont);
IF UserHitsReturn(linecount) THEN goto 999;
WriteString('Help file ='); WriteChar(' '); WriteString(helpname);
IF UserHitsReturn(linecount) THEN goto 999;
WriteString('Horizontal offset ='); WriteChar(' ');
WriteDimension(hoffset); WriteUnits;
IF UserHitsReturn(linecount) THEN goto 999;
WriteString('Vertical offset ='); WriteChar(' ');
WriteDimension(voffset); WriteUnits;
IF UserHitsReturn(linecount) THEN goto 999;
WriteString('Paper wd by ht ='); WriteChar(' ');
WriteDimension(paperwd); WriteUnits;
WriteString(' by'); WriteChar(' ');
WriteDimension(paperht); WriteUnits;
IF UserHitsReturn(linecount) THEN goto 999;
IF UserHitsReturn(linecount) THEN goto 999;
WriteString('Total fonts on ALL pages ='); WriteChar(' ');
WriteInt(totalfonts);
IF UserHitsReturn(linecount) THEN goto 999;
IF UserHitsReturn(linecount) THEN goto 999;
WriteString('Fonts: (if used on current page then total chars given)');
IF UserHitsReturn(linecount) THEN goto 999;
fontcount := 0;
thisfontinfo := fontlist;
WHILE thisfontinfo <> NIL DO
WITH thisfontinfo^ DO BEGIN
IF fontspeclen = 0 THEN (* need to build fontspec *)
BuildFontSpec(thisfontinfo); (* fontexists may become TRUE *)
WriteString(fontspec);
IF psfont THEN WritePtSize(scaledsize);
IF NOT fontexists THEN
WriteString(' does not exist!'); (* use dummyfont instead *)
IF fontused THEN BEGIN
fontcount := fontcount + 1;
WriteString(' (total chars ='); WriteChar(' ');
WriteInt(totalchars); WriteChar(')');
END;
IF UserHitsReturn(linecount) THEN goto 999;
thisfontinfo := nextfont;
END;
IF currDVIpage = 0 THEN
WriteString('You haven''t selected a page yet.')
ELSE BEGIN
WriteString('Total fonts on current page ='); WriteChar(' ');
WriteInt(fontcount);
END;
IF UserHitsReturn(linecount) THEN goto 999;
IF UserHitsReturn(linecount) THEN goto 999;
WriteString('Total rules on current page ='); WriteChar(' ');
WriteInt(totalrules);
IF speciallist <> NIL THEN BEGIN
IF UserHitsReturn(linecount) THEN goto 999;
IF UserHitsReturn(linecount) THEN goto 999;
WriteString('\special commands on current page:');
IF UserHitsReturn(linecount) THEN goto 999;
temp := speciallist;
WHILE temp <> NIL DO
WITH temp^ DO BEGIN
WriteString('At (');
WriteDimension(hp); WriteChar(',');
WriteDimension(vp); WriteString('):'); WriteChar(' ');
WriteString(special);
IF UserHitsReturn(linecount) THEN goto 999;
temp := nextspecial;
END;
END;
WriteLine;
WriteLine;
MoveToTextLine(bottoml);
WriteString('Hit RETURN key to resume page display:');
WriteBuffer;
REPEAT ReadChar(ch) UNTIL ch = CR;
999:
END; (* ShowStatistics *)
(******************************************************************************)
PROCEDURE ShowHelp;
(* Help information is displayed in lines 1 to bottoml-2.
We assume that bottoml is at least 3 and that VDU screen is at least
maxline characters wide.
*)
LABEL 888;
CONST
maxline = 80; (* SYSDEP: helpname should have <= maxline chars/line *)
maxlinem = maxline - 1;
VAR
helpfile : integer;
outline : ARRAY [0..maxlinem] OF CHAR;
i, lines, length, result : INTEGER;
ch, answer : CHAR;
BEGIN
length := Len(helpname);
IF length < maxstring THEN helpname[length] := CHR(0); (* terminate with NULL *)
helpfile := open(helpname, O_RDONLY, 0); (* read only *)
IF length < maxstring THEN helpname[length] := ' '; (* restore space *)
IF helpfile < 0 THEN BEGIN
ClearMessageLine;
WriteString('Couldn''t open help file'); WriteChar(' ');
WriteString(helpname); WriteChar('!');
WaitForReturn;
ClearMessageLine;
END
ELSE BEGIN
ClearScreen;
MoveToTextLine(1);
lines := 0;
WHILE TRUE DO BEGIN
IF read(helpfile,ch,1) = 0 THEN BEGIN (* SYSDEP: end of file *)
ClearTextLine(bottoml);
MoveToTextLine(bottoml);
WriteString('Hit RETURN key to resume page display:');
WriteBuffer;
REPEAT ReadChar(answer) UNTIL answer = CR;
goto 888;
END
ELSE IF lines >= (bottoml-2) THEN BEGIN (* blank line before prompt *)
ClearTextLine(bottoml);
MoveToTextLine(bottoml);
WriteString('Hit RETURN key to resume page display,');
WriteString(' or any other key for more help:');
WriteBuffer;
ReadChar(answer);
IF answer = CR THEN goto 888;
ClearScreen;
MoveToTextLine(1);
lines := 0; (* reset line count *)
END;
outline := ' ';
i := 0;
WHILE ch <> CR DO BEGIN
IF i < maxline THEN outline[i] := ch;
(* SYSDEP: check if eof occurs before eoln *)
IF read(helpfile,ch,1) = 0 THEN ch := CR;
i := i + 1;
END;
WriteString(outline); WriteLine;
lines := lines + 1;
END;
888:
result := Close(helpfile);
ClearScreen;
screenjustcleared := TRUE;
paintDVIStatus := TRUE;
paintWindowStatus := TRUE;
IF currDVIpage <> 0 THEN paintwindow := TRUE;
END;
END; (* ShowHelp *)
(******************************************************************************)
PROCEDURE DisplayPaperEdges;
(* Display visible outlines of the imaginary sheet of paper.
Thickness of outlines = 1 screen pixel no matter what the h and v scaling.
*)
LABEL 999;
CONST
edgepixel = '.'; (* black pixel for outlines on non-graphic VDUs;
note that VDU TeXtoASCII['.'] := '.' *)
VAR
top, bot, left, right, (* visible edges of paper in paper pixels *)
scaledtop, scaledleft, (* scaled visible edges in screen pixels *)
scaledbot, scaledright,
scaledheight, scaledwidth (* scaled width and height *)
: INTEGER;
BEGIN
(* first check if any part of paper is visible *)
IF papertop > windowbottom THEN goto 999;
IF paperbottom < windowtop THEN goto 999;
IF paperleft > windowright THEN goto 999;
IF paperright < windowleft THEN goto 999;
(* part or all of paper is visible, so return visible region *)
top := Max(papertop,windowtop);
bot := Min(paperbottom,windowbottom);
left := Max(paperleft,windowleft);
right := Min(paperright,windowright);
scaledtop := ScaleVpos(top - windowtop) + windowv;
scaledleft := ScaleHpos(left - windowleft) + windowh;
IF vscalefactor > 1.0 THEN
scaledbot := ScaleVpos(bot + 1 - windowtop) - 1 + windowv
ELSE
scaledbot := ScaleVpos(bot - windowtop) + windowv;
IF hscalefactor > 1.0 THEN
scaledright := ScaleHpos(right + 1 - windowleft) - 1 + windowh
ELSE
scaledright := ScaleHpos(right - windowleft) + windowh;
scaledheight := scaledbot - scaledtop + 1;
scaledwidth := scaledright - scaledleft + 1;
(* only show visible edges if they are also paper outlines *)
IF left = paperleft THEN
ShowRectangle(scaledleft, scaledtop, 1, scaledheight, edgepixel);
IF bot = paperbottom THEN
ShowRectangle(scaledleft, scaledbot, scaledwidth, 1, edgepixel);
IF top = papertop THEN
ShowRectangle(scaledleft, scaledtop, scaledwidth, 1, edgepixel);
IF right = paperright THEN
ShowRectangle(scaledright, scaledtop, 1, scaledheight, edgepixel);
999:
END; (* DisplayPaperEdges *)
(******************************************************************************)
FUNCTION RectangleVisible (intop, inbot, inleft, inright : INTEGER;
VAR outtop, outbot, outleft, outright : INTEGER
) : BOOLEAN;
(* Return TRUE iff part or all of given rectangle would be visible
in the current window. Iff so, then we also return the visible
region; the input and possible output rectangles are defined by their
top, bottom, left and right edges in paper pixel coordinates.
*)
BEGIN
IF allpagevisible THEN BEGIN (* all of rectangle must be visible *)
outtop := intop; outbot := inbot; outleft := inleft; outright := inright;
RectangleVisible := TRUE;
END
ELSE IF intop > windowbottom THEN RectangleVisible := FALSE
ELSE IF inbot < windowtop THEN RectangleVisible := FALSE
ELSE IF inleft > windowright THEN RectangleVisible := FALSE
ELSE IF inright < windowleft THEN RectangleVisible := FALSE
ELSE BEGIN
(* part or all of rectangle is visible, so return visible region *)
outtop := Max(intop,windowtop);
outbot := Min(inbot,windowbottom);
outleft := Max(inleft,windowleft);
outright := Min(inright,windowright);
RectangleVisible := TRUE;
END;
END; (* RectangleVisible *)
(******************************************************************************)
PROCEDURE DisplayRules;
(* Display all pixels in rules, regardless of current displaymode.
Rules will be displayed in the same order as in the DVI page (essentially
top-down and left-right) because of the way DVIReader builds a rulelist.
*)
LABEL 999;
CONST
rulepixel = '*'; (* black pixel for rules on non-graphic VDUs;
note that VDU sets TeXtoASCII['*'] := '*' *)
VAR
top, bottom, left, right, (* visible edges of rule *)
scaledtop, scaledleft, (* scaled visible edges *)
scaledbot, scaledright,
scaledwidth, scaledheight, (* scaled width and height *)
thisrule : INTEGER;
keyhit : CHAR; (* returned by BusyRead if TRUE *)
BEGIN
thisruleinfo := rulelist;
WHILE thisruleinfo <> NIL DO
WITH thisruleinfo^ DO BEGIN
thisrule := 0;
WHILE thisrule < rulecount DO BEGIN
WITH ruletable[thisrule] DO BEGIN
(* check if any part of rule is visible *)
(* vp,hp is bottom left corner of rule on page *)
IF RectangleVisible
(vp-ht+1,vp,hp,hp+wd-1, (* rule edges *)
top,bottom,left,right) (* visible rectangle *)
THEN BEGIN
(* show all pixels in this rectangle *)
scaledtop := ScaleVpos(top - windowtop) + windowv;
scaledleft := ScaleHpos(left - windowleft) + windowh;
IF vscalefactor > 1.0 THEN
scaledbot := ScaleVpos(bottom+1-windowtop) - 1 + windowv
ELSE
scaledbot := ScaleVpos(bottom-windowtop) + windowv;
IF hscalefactor > 1.0 THEN
scaledright := ScaleHpos(right+1-windowleft) - 1 + windowh
ELSE
scaledright := ScaleHpos(right-windowleft) + windowh;
scaledheight := scaledbot - scaledtop + 1;
scaledwidth := scaledright - scaledleft + 1;
ShowRectangle
(scaledleft, (* h coord of top left cnr *)
scaledtop, (* v coord of top left cnr *)
scaledwidth,
scaledheight,
rulepixel);
(* check keyboard after every visible rule *)
IF BusyRead(keyhit) THEN BEGIN
keyhit := Cap(keyhit);
IF (keyhit = Terse) AND (displaymode <> tersemode) THEN BEGIN
displaymode := tersemode;
StartText;
UpdateDVIStatusLine;
StartGraphics;
END
ELSE IF (keyhit = Box) AND (displaymode <> boxmode) THEN BEGIN
displaymode := boxmode;
StartText;
UpdateDVIStatusLine;
StartGraphics;
END
ELSE IF (keyhit = Full) AND
(displaymode <> fullmode) THEN BEGIN
displaymode := fullmode;
StartText;
UpdateDVIStatusLine;
StartGraphics;
END
ELSE IF keyhit = CR THEN BEGIN
useraborted := TRUE; (* checked in DisplayPage *)
goto 999;
END;
END;
END;
END;
thisrule := thisrule + 1;
END;
thisruleinfo := nextrule;
END;
999:
END; (* DisplayRules *)
(******************************************************************************)
FUNCTION PixelVisible (hpos, vpos : INTEGER) : BOOLEAN;
(* Return TRUE iff given paper pixel would be visible in current window. *)
BEGIN
IF allpagevisible THEN PixelVisible := TRUE
ELSE IF vpos < windowtop THEN PixelVisible := FALSE
ELSE IF vpos > windowbottom THEN PixelVisible := FALSE
ELSE IF hpos < windowleft THEN PixelVisible := FALSE
ELSE IF hpos > windowright THEN PixelVisible := FALSE
ELSE PixelVisible := TRUE;
END; (* PixelVisible *)
(******************************************************************************)
PROCEDURE TerseChar;
(* Display a quick and nasty representation of character only if ref pt visible.
Just how good the representation is depends on the capabilities of the VDU.
We don't bother checking if glyph is actually all white or non-existent.
*)
BEGIN
WITH thisfontinfo^ DO
WITH thischarinfo^.chartable[thischar] DO
IF PixelVisible(hp,vp) THEN (* ref pt of char is visible *)
ShowChar(ScaleHpos(hp - windowleft) + windowh,
ScaleVpos(vp - windowtop) + windowv,
CHR(code));
END; (* TerseChar *)
(******************************************************************************)
PROCEDURE BoxChar;
(* Display visible box outlines of glyph.
Thickness of outlines = 1 screen pixel no matter what the h and v scaling.
*)
LABEL 999;
VAR
vpmyo, hpmxo, (* vp-yo, hp-xo: glyph's top and left edges *)
top, bottom, left, right, (* visible edges of glyph *)
scaledtop, scaledleft, (* scaled visible edges *)
scaledbot, scaledright,
scaledheight, scaledwidth (* scaled width and height *)
: INTEGER;
ch : CHAR;
BEGIN
WITH thisfontinfo^ DO
WITH thischarinfo^.chartable[thischar] DO
WITH pixelptr^[code] DO BEGIN
IF mapadr = 0 THEN goto 999; (* glyph all white or absent *)
(* check if any part of glyph is visible *)
vpmyo := vp-yo;
hpmxo := hp-xo;
IF RectangleVisible
(vpmyo, vpmyo+ht-1, hpmxo, hpmxo+wd-1,(* glyph edges *)
top,bottom,left,right) (* visible part *)
THEN BEGIN
scaledtop := ScaleVpos(top - windowtop) + windowv;
scaledleft := ScaleHpos(left - windowleft) + windowh;
IF vscalefactor > 1.0 THEN
scaledbot := ScaleVpos(bottom + 1 - windowtop) - 1 + windowv
ELSE
scaledbot := ScaleVpos(bottom - windowtop) + windowv;
IF hscalefactor > 1.0 THEN
scaledright := ScaleHpos(right + 1 - windowleft) - 1 + windowh
ELSE
scaledright := ScaleHpos(right - windowleft) + windowh;
scaledheight := scaledbot - scaledtop + 1;
scaledwidth := scaledright - scaledleft + 1;
(* Only show edges that are also glyph outlines!
Following method reduces the number of ShowRectangle calls needed for
very small boxes.
*)
ch := CHR(code);
IF ((scaledheight < 3) AND (top = vpmyo) AND (bottom = vpmyo+ht-1)) OR
((scaledwidth < 3) AND (left = hpmxo) AND (right = hpmxo+wd-1)) THEN
ShowRectangle(scaledleft, scaledtop, scaledwidth, scaledheight, ch)
ELSE BEGIN
IF left = hpmxo THEN
ShowRectangle(scaledleft, scaledtop, 1, scaledheight, ch);
IF bottom = vpmyo+ht-1 THEN
ShowRectangle(scaledleft, scaledbot, scaledwidth, 1, ch);
IF top = vpmyo THEN
ShowRectangle(scaledleft, scaledtop, scaledwidth, 1, ch);
IF right = hpmxo+wd-1 THEN
ShowRectangle(scaledright, scaledtop, 1, scaledheight, ch);
END;
END;
END;
999:
END; (* BoxChar *)
(******************************************************************************)
PROCEDURE FullCharPS;
(* Display filled rectangle approximating the extent of PostScript glyph. *)
LABEL 999;
VAR
vpmyo, hpmxo, (* vp-yo, hp-xo: glyph's top and left edges *)
top, bottom, left, right, (* visible edges of glyph *)
scaledtop, scaledleft, (* scaled visible edges *)
scaledbot, scaledright,
scaledheight, scaledwidth (* scaled width and height *)
: INTEGER;
BEGIN
WITH thisfontinfo^ DO
WITH thischarinfo^.chartable[thischar] DO
WITH pixelptr^[code] DO BEGIN
IF mapadr = 0 THEN goto 999; (* glyph all white or absent *)
(* check if any part of glyph is visible *)
vpmyo := vp-yo;
hpmxo := hp-xo;
IF RectangleVisible
(vpmyo, vpmyo+ht-1, hpmxo, hpmxo+wd-1,(* glyph edges *)
top,bottom,left,right) (* visible part *)
THEN BEGIN
scaledtop := ScaleVpos(top - windowtop) + windowv;
scaledleft := ScaleHpos(left - windowleft) + windowh;
IF vscalefactor > 1.0 THEN
scaledbot := ScaleVpos(bottom + 1 - windowtop) - 1 + windowv
ELSE
scaledbot := ScaleVpos(bottom - windowtop) + windowv;
IF hscalefactor > 1.0 THEN
scaledright := ScaleHpos(right + 1 - windowleft) - 1 + windowh
ELSE
scaledright := ScaleHpos(right - windowleft) + windowh;
scaledheight := scaledbot - scaledtop + 1;
scaledwidth := scaledright - scaledleft + 1;
ShowRectangle(scaledleft, scaledtop,scaledwidth, scaledheight, CHR(code));
END;
END;
999:
END; (* FullCharPS *)
(******************************************************************************)
PROCEDURE NotFound (VAR fspec : string);
BEGIN
StartText;
ResetVDU; (* do before message since it might erase screen! *)
WriteString('Couldn''t open font'); WriteChar(' ');
WriteString(fspec); WriteChar('!'); WriteLine;
RestoreTerminal; exit(1);
END; (* NotFound *)
(******************************************************************************)
PROCEDURE FullChar;
(* Display all pixels in a glyph using bitmap from font file.
The algorithm avoids overlapping rows when vscalefactor < 1.0.
When hscalefactor < 1.0, it is not worth the extra code to avoid overlapping
runs of 1 bits because the majority of character glyphs have only one or two
runs per row.
*)
LABEL 666, 777, 888, 999;
CONST
maxviswords = 100;
maxviswordsm = maxviswords - 1;
(* 100 * 32 = 3200 bits = maximum pixel width of glyph!
If any fonts have glyphs wider than this then increase maxviswords.
*)
TYPE
(* SYSDEP: BITSET is 32 bit word with elements 31,30,29,...,0 *)
glyphrow = ARRAY [0..maxviswordsm] OF BITSET;
VAR
vpmyo, hpmxo, (* vp-yo, hp-xo: glyph's top and left edges *)
top, bottom, left, right, (* visible edges of glyph *)
scaledv, scalednextv, (* scaled vertical positions for rows *)
scaledh, (* scaled horizontal positions within row *)
scaledwidth, scaledheight, (* scaled width and height of row *)
thisrow, thisbit, (* in paper coordinates *)
wordsperrow, (* rows of bitmap are word aligned *)
firstbit, lastbit, (* somewhere in 0 .. wordsperrow*32-1 *)
firstword, lastword, (* somewhere in 0 .. wordsperrow-1 *)
endword, (* = visible words in row, - 1 *)
wordpos, (* 0 .. endword *)
bitpos, (* 31 .. 0 *)
i : INTEGER;
row : glyphrow; (* holds VISIBLE bits in one row of glyph;
possibly > one row if vscalefactor < 1.0 *)
ptr : int_or_bptr; (* pointer into bitmap *)
inrun : BOOLEAN; (* are we in a run of black pixels in row? *)
BEGIN
WITH thisfontinfo^ DO
WITH thischarinfo^.chartable[thischar] DO
WITH pixelptr^[code] DO BEGIN
IF mapadr = 0 THEN goto 999; (* glyph all white or absent *)
(* check if any part of glyph is visible *)
vpmyo := vp-yo;
hpmxo := hp-xo;
IF RectangleVisible
(vpmyo,vpmyo+ht-1,hpmxo,hpmxo+wd-1, (* glyph edges *)
top,bottom,left,right) (* visible part *)
THEN BEGIN
IF bitmap.mptr = NIL THEN BEGIN
IF NOT fontopen THEN BEGIN
IF fontexists THEN BEGIN
IF NOT OpenFontFile(fontspec) THEN NotFound(fontspec);
END
ELSE
IF NOT OpenFontFile(dummyfont) THEN NotFound(dummyfont);
fontopen := TRUE; (* only open font once *)
END;
GetBitmap(ht, wd, (* dimensions of bitmap *)
mapadr, (* bitmap info in font file *)
bitmap); (* starting address of bitmap *)
END;
wordsperrow := (wd + 31) DIV 32; (* words in one row of bitmap *)
firstbit := left-hpmxo; (* first visible bit *)
lastbit := right-hpmxo; (* last visible bit *)
firstword := firstbit DIV 32; (* first visible word *)
lastword := lastbit DIV 32; (* last visible word *)
endword := lastword - firstword;
(* we impose a limit on width of glyph (unlikely to be exceeded) *)
{ DEBUG
IF endword > maxviswordsm THEN BEGIN
StartText;
ClearMessageLine;
WriteString('Glyph'); WriteChar(' '); WriteInt(code);
WriteString(' too wide!');
WaitForReturn;
StartGraphics;
END;
GUBED }
(* set the visible words in row to 0 *)
FOR i := 0 TO endword DO row[i] := [];
(* calculate scaled v coord of first visible row *)
scaledv := ScaleVpos(top - windowtop) + windowv;
(* only consider visible rows; thisrow := top to bottom *)
thisrow := top;
WHILE TRUE DO BEGIN
(* move to first byte of first visible word in this row *)
ptr.int := bitmap.int +
4 * ((thisrow - vpmyo) * wordsperrow + firstword);
(* get row of visible words from bitmap and OR with row array *)
wordpos := 0;
WHILE TRUE DO BEGIN
row[wordpos] := ptr.bptr^ + row[wordpos]; (* set union *)
IF wordpos = endword THEN goto 888;
wordpos := wordpos + 1;
ptr.int := ptr.int + 4; (* next word *)
END;
888:
(* calculate scaled v coord of next row *)
scalednextv := ScaleVpos(thisrow + 1 - windowtop) + windowv;
scaledheight := scalednextv - scaledv;
IF (scaledheight > 0) OR (thisrow = bottom) THEN BEGIN
(* display black pixels in row, doing any h/v expansion *)
IF scaledheight < 1 THEN scaledheight := 1; (* avoid 0 *)
inrun := FALSE;
bitpos := 31 - (firstbit MOD 32); (* 31..0 *)
wordpos := 0;
(* only consider visible bits; thisbit := left to right *)
thisbit := left;
WHILE TRUE DO BEGIN
IF bitpos IN row[wordpos] THEN BEGIN (* start/continue run *)
IF NOT inrun THEN BEGIN (* remember start of run *)
inrun := TRUE;
scaledh := ScaleHpos(thisbit - windowleft) + windowh;
END;
END
ELSE IF inrun THEN BEGIN (* 0 bit has ended run *)
inrun := FALSE;
scaledwidth := ScaleHpos(thisbit - windowleft) + windowh
- scaledh;
IF scaledwidth < 1 THEN scaledwidth := 1; (* avoid 0 *)
ShowRectangle(scaledh,scaledv,
scaledwidth,scaledheight,CHR(code));
END;
IF thisbit = right THEN goto 777; (* exit bit loop *)
IF bitpos = 0 THEN BEGIN
wordpos := wordpos + 1;
bitpos := 31;
END
ELSE (* look at next bit in word *)
bitpos := bitpos - 1;
thisbit := thisbit + 1;
END; (* bit loop *)
777:
IF inrun THEN BEGIN (* show run at end of row *)
scaledwidth := ScaleHpos(thisbit + 1 - windowleft) + windowh
- scaledh;
IF scaledwidth < 1 THEN scaledwidth := 1; (* avoid 0 *)
ShowRectangle(scaledh,scaledv,
scaledwidth,scaledheight,CHR(code));
END;
IF thisrow = bottom THEN goto 666; (* exit row loop *)
(* else reset the visible words in row to 0 *)
FOR i := 0 TO endword DO row[i] := [];
END;
scaledv := scalednextv;
thisrow := thisrow + 1;
END; (* row loop *)
666:
END;
END;
999:
END; (* FullChar *)
(******************************************************************************)
PROCEDURE DisplayChars;
(* Display all characters on a font by font basis. How characters will be
represented depends on the current displaymode (which the user can change
while the window is being updated by typing the Tesre/Box/Full commands).
Fonts will be displayed in order of ascending totalchars (due to SortFonts).
Characters in a font will be displayed in a top-down, left-right manner
because of the way DVIReader builds a charlist.
*)
LABEL 999;
VAR keyhit : CHAR; (* check for abort or mode change *)
BEGIN
thisfontinfo := fontlist;
WHILE thisfontinfo <> unusedfont DO
(* SortFont makes sure we only consider used fonts *)
WITH thisfontinfo^ DO BEGIN
fontopen := FALSE; (* might be set in FullChar *)
(* Some VDUs may be able to simulate the given font.
To help the VDU select appropriately sized characters, we need to
pass the scaledsize of the font (converted to unscaled paper pixels),
the overall mag, and the current h/vscalefactors.
*)
LoadFont(fontspec,
PixelRound(scaledsize),
mag/1000.0,
hscalefactor,
vscalefactor);
thischarinfo := charlist;
WHILE thischarinfo <> NIL DO BEGIN (* display chars in chartable *)
WITH thischarinfo^ DO BEGIN
thischar := 0;
WHILE thischar < charcount DO BEGIN
IF displaymode = fullmode THEN BEGIN
IF psfont THEN FullCharPS ELSE FullChar
END
ELSE IF displaymode = tersemode THEN
TerseChar
ELSE
BoxChar;
(* check for abort or mode change *)
IF BusyRead(keyhit) THEN BEGIN
keyhit := Cap(keyhit);
IF (keyhit = Terse) AND (displaymode <> tersemode) THEN BEGIN
displaymode := tersemode;
StartText;
UpdateDVIStatusLine;
StartGraphics;
END
ELSE IF (keyhit = Box) AND (displaymode <> boxmode) THEN BEGIN
displaymode := boxmode;
StartText;
UpdateDVIStatusLine;
StartGraphics;
END
ELSE IF (keyhit = Full) AND
(displaymode <> fullmode) THEN BEGIN
displaymode := fullmode;
StartText;
UpdateDVIStatusLine;
StartGraphics;
END
ELSE IF keyhit = CR THEN BEGIN
IF fontopen THEN CloseFontFile;
(* no need to set useraborted; DisplayRules done first *)
goto 999;
END;
END;
thischar := thischar + 1;
END;
thischarinfo := nextchar;
END;
END;
IF fontopen THEN CloseFontFile;
thisfontinfo := nextfont;
END;
999:
END; (* DisplayChars *)
(******************************************************************************)
PROCEDURE PaperMessage;
(* Called by CheckPageEdges to remind user of the paper size. *)
BEGIN
CASE currentunits OF
inunits : WriteString('in');
cmunits : WriteString('cm');
mmunits : WriteString('mm');
pcunits : WriteString('pc');
ptunits : WriteString('pt');
pxunits : WriteString('px')
END;
WriteString('! (Paper is'); WriteChar(' ');
WriteDimension(paperwd); WriteString(' by'); WriteChar(' ');
WriteDimension(paperht); WriteChar(')');
WaitForReturn;
ClearMessageLine;
END; (* PaperMessage *)
(******************************************************************************)
PROCEDURE CheckPageEdges;
(* One or more page edges do not fall within the paper edges.
This routine is called after the page & paper have been displayed so
user can see how bad the problem is.
*)
BEGIN
IF minhp < paperleft THEN BEGIN
ClearMessageLine;
WriteString('Page beyond left edge by'); WriteChar(' ');
WriteDimension(paperleft - minhp);
PaperMessage;
END;
IF maxhp > paperright THEN BEGIN
ClearMessageLine;
WriteString('Page beyond right edge by'); WriteChar(' ');
WriteDimension(maxhp - paperright);
PaperMessage;
END;
IF minvp < papertop THEN BEGIN
ClearMessageLine;
WriteString('Page above top edge by'); WriteChar(' ');
WriteDimension(papertop - minvp);
PaperMessage;
END;
IF maxvp > paperbottom THEN BEGIN
ClearMessageLine;
WriteString('Page below bottom edge by'); WriteChar(' ');
WriteDimension(maxvp - paperbottom);
PaperMessage;
END;
END; (* CheckPageEdges *)
(******************************************************************************)
PROCEDURE DisplayPage;
(* Display page in window region based on window location and size,
and displaymode. This routine is only called if paintwindow is TRUE
after all commands have been processed.
*)
BEGIN
IF screenjustcleared THEN BEGIN (* avoid doing it again *)
IF paintDVIStatus THEN UpdateDVIStatusLine;
IF paintWindowStatus THEN UpdateWindowStatusLine;
END
ELSE BEGIN
ClearScreen;
UpdateDVIStatusLine;
UpdateWindowStatusLine;
END;
StartGraphics;
DisplayPaperEdges;
StartText;
IF pageempty THEN BEGIN
ClearMessageLine;
WriteString('Page is empty.');
END
ELSE IF outsidepage THEN BEGIN
IF pageoffpaper THEN CheckPageEdges;
ClearMessageLine;
WriteString('Window is'); WriteChar(' ');
IF windowtop > maxvp THEN BEGIN
WriteString('below'); WriteChar(' ');
IF (windowleft > maxhp) OR (windowleft < minhp - scaledwd + 1) THEN BEGIN
WriteString('and'); WriteChar(' ');
END;
END
ELSE IF windowtop < minvp - scaledht + 1 THEN BEGIN
WriteString('above'); WriteChar(' ');
IF (windowleft > maxhp) OR (windowleft < minhp - scaledwd + 1) THEN BEGIN
WriteString('and'); WriteChar(' ');
END;
END;
IF windowleft > maxhp THEN BEGIN
WriteString('to the right of'); WriteChar(' ');
END
ELSE IF windowleft < minhp - scaledwd + 1 THEN BEGIN
WriteString('to the left of'); WriteChar(' ');
END;
WriteString('page.');
END
ELSE BEGIN
(* Page is not empty and part or all of it is visible. *)
StartGraphics;
useraborted := FALSE;
DisplayRules;
IF NOT useraborted THEN DisplayChars;
StartText;
IF pageoffpaper THEN CheckPageEdges;
IF allpagevisible THEN BEGIN
ClearMessageLine;
WriteString('Entire page is visible.');
END;
END;
END; (* DisplayPage *)
(******************************************************************************)
PROCEDURE NextCommandLine;
(* Prompt user for next command line, parse response and call the
appropriate command handler for each command in the line.
*)
LABEL 888, 999;
VAR n : INTEGER; (* returned by GetInteger call *)
BEGIN
ClearTextLine(commandl);
MoveToTextLine(commandl);
WriteString(commprompt);
WriteBuffer;
ReadString(commstring); (* read new command line *)
ClearMessageLine; (* erase message line at this stage *)
commlen := maxstring;
commpos := 0;
WHILE commlen > 0 DO BEGIN
IF commstring[commlen-1] <> ' ' THEN goto 888;
commlen := commlen - 1; (* ignore any trailing spaces *)
END;
888:
(* initialize flags for multiple command processing *)
badcommand := FALSE;
paintWindowStatus := FALSE;
paintDVIStatus := FALSE;
paintwindow := FALSE;
screenjustcleared := FALSE;
pageoffpaper := FALSE;
WHILE (commpos < commlen) AND (NOT badcommand) DO BEGIN
(* next command is defined by the next non-space character in commstring *)
WHILE commstring[commpos] = ' ' DO BEGIN
commpos := commpos + 1; (* ignore any spaces *)
END;
command := Cap(commstring[commpos]);
CASE command OF
Window : BEGIN
commpos := commpos + 1;
WindowMove;
IF NOT badcommand THEN paintWindowStatus := TRUE;
END;
Up,
Down : BEGIN
commpos := commpos + 1;
WindowUpDown;
paintWindowStatus := TRUE;
END;
Left,
Right : BEGIN
commpos := commpos + 1;
WindowLeftRight;
paintWindowStatus := TRUE;
END;
Hsize : BEGIN
commpos := commpos + 1;
SetWindowWidth;
NewLocation(windowleft,windowtop);
paintWindowStatus := TRUE;
END;
Vsize : BEGIN
commpos := commpos + 1;
SetWindowHeight;
NewLocation(windowleft,windowtop);
paintWindowStatus := TRUE;
END;
AutoView : BEGIN
commpos := commpos + 1;
SetAutoView;
IF NOT badcommand THEN paintDVIStatus := TRUE;
END;
ZoomInOut : BEGIN
commpos := commpos + 1;
ZoomWindow;
IF NOT badcommand THEN NewLocation(windowleft,windowtop);
IF NOT badcommand THEN paintWindowStatus := TRUE;
END;
NextPage : BEGIN
commpos := commpos + 1;
IF NextPageFound THEN ProcessPage;
END;
'0','1','2','3','4','5','6','7','8','9' :
IF GetInteger(commstring,commlen,commpos,n) THEN
(* must be true, and commpos now after last digit *)
IF DVIPageFound(n) THEN
ProcessPage;
TeXpage : IF TeXPageFound THEN ProcessPage;
(* commpos incremented in ParseTeXpage *)
Forwards : BEGIN
commpos := commpos + 1;
ascending := TRUE;
paintDVIStatus := TRUE;
END;
Backwards : BEGIN
commpos := commpos + 1;
ascending := FALSE;
paintDVIStatus := TRUE;
END;
Terse : BEGIN
commpos := commpos + 1;
displaymode := tersemode;
paintDVIStatus := TRUE;
IF currDVIpage <> 0 THEN paintwindow := TRUE;
END;
Box : BEGIN
commpos := commpos + 1;
displaymode := boxmode;
paintDVIStatus := TRUE;
IF currDVIpage <> 0 THEN paintwindow := TRUE;
END;
Full : BEGIN
commpos := commpos + 1;
displaymode := fullmode;
paintDVIStatus := TRUE;
IF currDVIpage <> 0 THEN paintwindow := TRUE;
END;
Ic, Cm, Mm,
PcPtPx : BEGIN
commpos := commpos + 1;
ChangeUnits;
IF NOT badcommand THEN paintWindowStatus := TRUE;
END;
Help : BEGIN
commpos := commpos + 1;
ShowHelp;
END;
Show : BEGIN
commpos := commpos + 1;
ShowStatistics;
ClearScreen;
screenjustcleared := TRUE;
paintDVIStatus := TRUE;
paintWindowStatus := TRUE;
IF currDVIpage <> 0 THEN paintwindow := TRUE;
END;
Quit : goto 999;
OTHERWISE
commpos := commpos + 1;
ClearMessageLine;
WriteString('Unknown command! Type'); WriteChar(' ');
WriteChar(Help); WriteString(' for help.');
BadCommandMessage;
END;
END;
IF paintwindow THEN
DisplayPage (* only update window after processing all commands *)
ELSE BEGIN
IF paintDVIStatus THEN UpdateDVIStatusLine;
IF paintWindowStatus THEN UpdateWindowStatusLine;
END;
999:
END; (* NextCommandLine *)
(******************************************************************************)
PROCEDURE Finish;
BEGIN
CloseDVIFile;
ClearScreen;
MoveToTextLine(1);
WriteLine;
ResetVDU;
RestoreTerminal; exit(0); (* halt with success *)
END; (* Finish *)
(******************************************************************************)
BEGIN
InitScreenIO; (* SYSDEP: sets cbreak on & echo off *)
InitOptions; (* init DVIname and command options *)
InitDVIReader;
InitFontReader;
OpenDVIFile(DVIname); (* and read DVImag etc. *)
IF mag = 0 THEN mag := DVImag; (* use DVImag *)
SetConversionFactor(resolution,mag); (* for DVIReader *)
InitVDU; (* init windowwd/ht etc. *)
Initialize;
StartText;
ClearScreen;
UpdateDVIStatusLine;
UpdateWindowStatusLine;
MoveToTextLine(messagel);
WriteString(version);
REPEAT
NextCommandLine; (* parse and execute command(s) *)
UNTIL command = Quit;
Finish;
END. (* DVItoVDU *)